﻿namespace HashSum
{
    using System;
    using System.Drawing;
    using System.IO;
    using System.Security.Cryptography;
    using ImageDupFinder.PluginCore;

    /// <summary>
    /// Class representing sha1 hashsum feature. 
    /// </summary>
    public class Sha1Sum : IFeature
    {
        /// <summary>
        /// feature name
        /// </summary>
        public const string FeatureName = "hash (sha1)";

        /// <summary>
        /// image hash
        /// </summary>
        private readonly string hash;

        /// <summary>
        /// feature calculated state.
        /// </summary>
        private bool calculated = false;

        /// <summary>
        /// Initializes a new instance of the Sha1Sum class.
        /// </summary>
        /// <param name="image">Image used in feature extraction</param>
        public Sha1Sum(Bitmap image)
        {
            byte[] byteArray = ImageToByte2(image);
            using (SHA1CryptoServiceProvider pr = new SHA1CryptoServiceProvider())
            {
                this.hash = Convert.ToBase64String(pr.ComputeHash(byteArray));
            }

            calculated = true;
        }

        /// <summary>
        /// Gets image hash
        /// </summary>
        public string Hash
        {
            get { return hash; }
        }

        #region IFeature Members

        /// <summary>
        /// Gets a value indicating whether feature is calculated.
        /// </summary>
        public bool IsCalculated
        {
            get { return calculated; }
        }

        /// <summary>
        /// Gets feature name.
        /// </summary>
        public string Name
        {
            get { return FeatureName; }
        }

        /// <summary>
        /// Calculate similarity between two SHA1 features.
        /// </summary>
        /// <param name="other">Second feature used in calcualtion</param>
        /// <returns>Similarity in range 0 - 1, where 0 means "identical" and 1 means "completly different"</returns>
        public float GetSimilarity(IFeature other)
        {
            if (!(other is Sha1Sum) || !other.IsCalculated || !this.IsCalculated)
            {
                return 1;
            }

            Sha1Sum fr = other as Sha1Sum;
            return (hash == fr.Hash) ? 0 : 1;
        }

        #endregion

        /// <summary>
        /// Converts bitmap to byte array.
        /// </summary>
        /// <param name="img">image to convert</param>
        /// <returns>image as byte array</returns>
        private byte[] ImageToByte2(Bitmap img)
        {
            byte[] byteArray = new byte[0];
            using (MemoryStream stream = new MemoryStream())
            {
                img.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
                stream.Close();

                byteArray = stream.ToArray();
            }

            return byteArray;
        }
    }
}
